package com.cheeven.cwliu.citation.analysis;

import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class AnalyseCSVFiles {

	static String checkDictionary(String s, List<String> dict) {
		if (s == null) {
			return null;
		}
		s = s.trim().toUpperCase();
		int i = dict.indexOf(s);
		if (i != -1) {
			return dict.get(i);
		} else {
			dict.add(s);
			return s;
		}
	}

	static Integer getInteger(String s) {
		if (s == null || s.isEmpty()) {
			return null;
		}
		Integer i = new Integer(s.trim());
		return i;
	}

	static Double getDouble(String s) {
		if (s == null || s.isEmpty()) {
			return null;
		}
		Double i = new Double(s.trim());
		return i;
	}

	public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException, IOException {

		ArrayList<String> titles = new ArrayList<String>();
		ArrayList<String> authors = new ArrayList<String>();
		ArrayList<String> sourceTitles = new ArrayList<String>();
		ArrayList<String> specialIssues = new ArrayList<String>();
		ArrayList<String> dois = new ArrayList<String>();
		ArrayList<Record> records = new ArrayList<Record>();
		LinkedList<String[]> exceptions = new LinkedList<String[]>();

		String status = "0. Initialisating...";
		Logger.getLogger(
				AnalyseCSVFiles.class.getName()).log(
				Level.INFO,
				status);
		try {
			/*
			 String base = "C:\\Users\\ctsai\\Downloads\\CitationDownload\\output\\AdministrativeScienceQuarterly\\";
			 args = new String[]{
			 base + "citation-report-1-500.csv",
			 base + "citation-report-501-1000.csv",
			 base + "citation-report-1001-1500.csv",
			 base + "citation-report-1501-2000.csv",
			 base + "citation-report-2001-2500.csv",
			 base + "citation-report-2501-3000.csv",
			 base + "citation-report-3001-3378.csv",};
			 */
			for (String arg : args) {

				try {
					status = "1. Read file: " + arg;
					Logger.getLogger(
							AnalyseCSVFiles.class.getName()).log(
							Level.INFO,
							status);

					CSVReader csv = new CSVReader(new FileReader(arg));

					// read the header line
					status = "2. Read header line";
					String[] headerData = csv.readNext();
					String[] lineData = null;

					// read each line of data
					status = "3. Read each line of data";
					while ((lineData = csv.readNext()) != null) {
						try {

							Record record = new Record();
							records.add(record);

							status = "3.1. Read title";
							record.setTitle(checkDictionary(lineData[0], titles));

							status = "3.2. Read authors";
							String people = lineData[1];
							if (people != null) {
								String[] ps = people.split(";");
								for (String p : ps) {
									p = checkDictionary(p, authors);
									record.getAuthors().add(p);
								}
							}

							status = "3.3. Read source title";
							record.setSourceTitle(checkDictionary(lineData[5], sourceTitles));

							status = "3.4. Read publication date";
							String pubDate = lineData[6];
							if (pubDate != null) {
								int d = pubDate.indexOf(" ");
								if (d != -1) {
									String month = pubDate.substring(0, d).trim().toUpperCase();
									String year = pubDate.substring(d + 1);
									record.setPublicationMonth("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC".indexOf(month) / 3);
									record.setPublicationYear(getInteger(year));
								} else {
									record.setPublicationYear(getInteger(pubDate));
								}
							}
							status = "3.5. Read publication year";
							String year = lineData[7];
							if (year != null) {
								int y = Integer.parseInt(year);
								if (record.getPublicationYear() != null) {
									if (record.getPublicationYear() != y) {
										throw new RuntimeException("Wrong publication year for " + year + ", " + record.getPublicationYear() + ": " + record.getTitle());
									}
								} else {
									record.setPublicationYear(y);
								}
							}

							status = "3.6. Read publication volume";
							record.setVolume(getInteger(lineData[8]));
							status = "3.7. Read publication issue";
							record.setIssue(getInteger(lineData[9]));
							status = "3.8. Read publication special issue";
							record.setSpecialIssue(checkDictionary(lineData[12], specialIssues));
							status = "3.9. Read publication beginning page";
							record.setBeginningPage(getInteger(lineData[13]));
							status = "3.10. Read publication ending page";
							record.setEnddingPage(getInteger(lineData[14]));
							status = "3.11. Read publication article number";
							record.setArticleNumber(getInteger(lineData[15]));
							status = "3.12. Read publication DOI";
							record.setDOI(checkDictionary(lineData[16], dois));
							status = "3.13. Read publication total citation";
							record.setTotalCitations(getInteger(lineData[19]));

						} catch (Exception e) {
							Logger.getLogger(
									AnalyseCSVFiles.class.getName()).log(
									Level.WARNING,
									arg + ":" + status + ":" + Arrays.asList(lineData), e);
							exceptions.add(lineData);
						}
					}

					status = "4. Show temporary result at end of file: " + arg;
					Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
					Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total records: {0}", records.size());
					Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total titles: {0}", titles.size());
					Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total authurs: {0}", authors.size());
					Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total source titles: {0}", sourceTitles.size());
					Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total special issues: {0}", specialIssues.size());
				} catch (Exception e) {
					Logger.getLogger(
							AnalyseCSVFiles.class.getName()).log(
							Level.WARNING,
							arg + ":" + status, e);

				}
			}

			status = "5. Show complete result";
			Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
			Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total records: {0}", records.size());
			Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total titles: {0}", titles.size());
			Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total authurs: {0}", authors.size());
			Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total source titles: {0}", sourceTitles.size());
			Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Total special issues: {0}", specialIssues.size());
		} catch (Exception e) {
			Logger.getLogger(
					AnalyseCSVFiles.class.getName()).log(
					Level.WARNING,
					status, e);

		}
		
		File analysisFolder = new File("analysis");
		if(!analysisFolder.exists()) {
			analysisFolder.mkdirs();
		}

		status = "6. Produce Exception Report";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter exceptionCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "exceptions.csv")));
		exceptionCSV.writeAll(exceptions);
		exceptionCSV.flush();
		exceptionCSV.close();

		status = "7. Produce Title Dictionary";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter titleCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "titles.csv")));
		titleCSV.writeNext(new String[]{"id", "title"});
		for (int i = 0; i < titles.size(); i++) {
			titleCSV.writeNext(new String[]{String.valueOf(i), titles.get(i)});
		}
		titleCSV.flush();
		titleCSV.close();

		status = "8. Produce Author Dictionary";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter authorCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "authors.csv")));
		authorCSV.writeNext(new String[]{"id", "author"});
		for (int i = 0; i < authors.size(); i++) {
			authorCSV.writeNext(new String[]{String.valueOf(i), authors.get(i)});
		}
		authorCSV.flush();
		authorCSV.close();

		status = "9. Produce Source Title Dictionary";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter sourceTitleCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "sourceTitles.csv")));
		sourceTitleCSV.writeNext(new String[]{"id", "source title"});
		for (int i = 0; i < sourceTitles.size(); i++) {
			sourceTitleCSV.writeNext(new String[]{String.valueOf(i), sourceTitles.get(i)});
		}
		sourceTitleCSV.flush();
		sourceTitleCSV.close();

		status = "10. Produce Special Issue Dictionary";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter specialIssuesCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "specialIssues.csv")));
		specialIssuesCSV.writeNext(new String[]{"id", "special issue"});
		for (int i = 0; i < specialIssues.size(); i++) {
			specialIssuesCSV.writeNext(new String[]{String.valueOf(i), specialIssues.get(i)});
		}
		specialIssuesCSV.flush();
		specialIssuesCSV.close();

		status = "10. Produce DOI Dictionary";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter doisCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "dois.csv")));
		doisCSV.writeNext(new String[]{"id", "special issue"});
		for (int i = 0; i < dois.size(); i++) {
			doisCSV.writeNext(new String[]{String.valueOf(i), dois.get(i)});
		}
		doisCSV.flush();
		doisCSV.close();

		status = "11. How many authors can there be?";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		int authorCount = 0;
		for (int i = 0; i < records.size(); i++) {
			authorCount = Math.max(authorCount, records.get(i).getAuthors().size());
		}
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, "Max authors count: {0}", authorCount);

		status = "12. Produce Result Report";
		Logger.getLogger(AnalyseCSVFiles.class.getName()).log(Level.INFO, status);
		CSVWriter recordsCSV = new CSVWriter(new FileWriter(new File(analysisFolder, "results.csv")));
		recordsCSV.writeNext(new String[]{
					"title", "sourceTitle", "publicationMonth", "publicationYear", "volume",
					"issue", "specialIssue", "beginningPage", "endingPage", "articleNumber",
					"DOI", "totalCitations",
					"author1", "author2", "author3", "author4", "author5", "author6", "author7", "author8", "author9", "author10"
				});
		for (int i = 0; i < records.size(); i++) {
			Record r = records.get(i);

			recordsCSV.writeNext(new String[]{
						String.valueOf(titles.indexOf(r.getTitle())),
						String.valueOf(sourceTitles.indexOf(r.getSourceTitle())),
						((r.getPublicationMonth() == null) ? null : String.valueOf(r.getPublicationMonth())),
						((r.getPublicationYear() == null) ? null : String.valueOf(r.getPublicationYear())),
						((r.getVolume() == null) ? null : String.valueOf(r.getVolume())),
						((r.getIssue() == null) ? null : String.valueOf(r.getIssue())),
						String.valueOf(specialIssues.indexOf(r.getSpecialIssue())),
						((r.getBeginningPage() == null) ? null : String.valueOf(r.getBeginningPage())),
						((r.getEnddingPage() == null) ? null : String.valueOf(r.getEnddingPage())),
						((r.getArticleNumber() == null) ? null : String.valueOf(r.getArticleNumber())),
						String.valueOf(dois.indexOf(r.getDOI())),
						((r.getTotalCitations() == null) ? null : String.valueOf(r.getTotalCitations())),
						((r.getAuthors().size() > 0) ? (String.valueOf(authors.indexOf(r.getAuthors().get(0)))) : (null)),
						((r.getAuthors().size() > 1) ? (String.valueOf(authors.indexOf(r.getAuthors().get(1)))) : (null)),
						((r.getAuthors().size() > 2) ? (String.valueOf(authors.indexOf(r.getAuthors().get(2)))) : (null)),
						((r.getAuthors().size() > 3) ? (String.valueOf(authors.indexOf(r.getAuthors().get(3)))) : (null)),
						((r.getAuthors().size() > 4) ? (String.valueOf(authors.indexOf(r.getAuthors().get(4)))) : (null)),
						((r.getAuthors().size() > 5) ? (String.valueOf(authors.indexOf(r.getAuthors().get(5)))) : (null)),
						((r.getAuthors().size() > 6) ? (String.valueOf(authors.indexOf(r.getAuthors().get(6)))) : (null)),
						((r.getAuthors().size() > 7) ? (String.valueOf(authors.indexOf(r.getAuthors().get(7)))) : (null)),
						((r.getAuthors().size() > 8) ? (String.valueOf(authors.indexOf(r.getAuthors().get(8)))) : (null)),
						((r.getAuthors().size() > 9) ? (String.valueOf(authors.indexOf(r.getAuthors().get(9)))) : (null))
					});
		}
		recordsCSV.flush();
		recordsCSV.close();


	}
}
